/*
 * Copyright 2011-2012 by The Regents of the University of California Licensed
 * under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. you may obtain a copy of the
 * License from
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package edu.ucsd.db.bassarisk.query.ast;

import java.util.ArrayList;
import java.util.List;

import edu.ucsd.db.bassarisk.exception.VisitorException;
import edu.ucsd.db.bassarisk.query.ast.SyntaxExpressions.NonterminalSyntaxExpression;
import edu.ucsd.db.bassarisk.query.ast.SyntaxExpressions.SyntaxExpression;
import edu.ucsd.db.bassarisk.query.ast.SyntaxExpressions.TerminalSyntaxExpression;

/**
 * Several types of expressions in the user syntax allow multiple
 * subExpressions. This, however, is syntactic sugar and is not supported by the
 * concrete AST. This transformation de-sugars the user query before expressions
 * are resolved into concrete AST types to inject implied boolean conjunctions
 * below all expressions other than Boolean AND and Boolean OR.
 */
public class DesugarImpliedConjunction implements
    SyntaxExpressionVisitor<SyntaxExpression, Void> {
  @Override
  public SyntaxExpression
      visitNonterminalAbstractExpression(final NonterminalSyntaxExpression expr,
                                         final Void args) throws VisitorException {
    List<SyntaxExpression> oldSubExprs = expr.getSubExpressions();
    if (expr.getName().equals("AND") || expr.getName().equals("OR")
        || oldSubExprs.size() == 1) {
      // Then no transformation is needed
      List<SyntaxExpression> newSubExprs = new ArrayList<SyntaxExpression>();
      for (SyntaxExpression subExpr : oldSubExprs) {
        newSubExprs.add(subExpr.accept(this, args));
      }
      oldSubExprs.clear();
      oldSubExprs.addAll(newSubExprs);
      return expr;
    } else {
      // Then we simply insert an "AND" exression which gathers all the inputs.
      List<String> emptyArgs = new ArrayList<String>();
      NonterminalSyntaxExpression newSubExpr =
          new NonterminalSyntaxExpression("AND", emptyArgs, oldSubExprs);
      newSubExpr.setDebugInfo(expr.getStartLine(), expr.getStartColumn());
      oldSubExprs.clear();
      oldSubExprs.add(newSubExpr.accept(this, args));
      return expr;
    }
  }

  @Override
  public SyntaxExpression
      visitTerminalAbstractExpression(final TerminalSyntaxExpression expr,
                                      final Void args) {
    return expr;
  }
}
